/**
* @file whiskerWeaving.cpp
* Fev, 2014
* 
* @brief class to create apply whisker Weaving algorithm.
* 
* @author Antonio Miranda (amiranda@tecgraf.puc-rio.br )
* 
* @see 
*/

// includes
//----------

#include "whiskerWeaving.h"

//
//////////////////////////////////////////////////////////////////////////
whiskerWeaving::whiskerWeaving(void)
{
  m_topol = NULL;
}

//
//////////////////////////////////////////////////////////////////////////
whiskerWeaving::whiskerWeaving( cTopology *top )
{
  m_topol = top;
}

//
//////////////////////////////////////////////////////////////////////////
whiskerWeaving::~whiskerWeaving(void)
{
}

//
//////////////////////////////////////////////////////////////////////////
void whiskerWeaving::process()
{
  int i, flag, curr_edge;

  // build loops
  int num_edges = m_topol->NumEdges();
  
  // mark all edges
  for (i = 0; i < num_edges; ++i)
    m_topol->SetEdgeInfo (i, -1);

  for (curr_edge = 0; curr_edge < num_edges; ++curr_edge)
  {
    flag = m_topol->GetEdgeInfo(curr_edge);
    if (flag == -1)
    {
      loop cp;
      if (buildLoop (curr_edge, cp))
      {
        loops.push_back(cp);
      }
    }
  }


  // update adjacent loops
  vector <int> adj_loops_to_face;
  int nfaces = m_topol->NumElems();
  adj_loops_to_face.assign (nfaces*2, -1);

  // for all loops
  int curr_face;
  for (size_t i = 0; i < loops.size(); ++i)
  {
    for (size_t j = 0; j < loops[i].peaces.size(); ++j)
    {
      curr_face = loops[i].peaces[j].face;
      if (adj_loops_to_face[curr_face*2+0] == -1)
        adj_loops_to_face[curr_face*2+0] = (int) i;
      else
        adj_loops_to_face[curr_face*2+1] = (int) i;
    }
  }



}

//
//////////////////////////////////////////////////////////////////////////
bool whiskerWeaving::buildLoop (int curr_edge, loop &curr_loop)
{
  int opp_face, opp_edge, last_edge, last_face;
  size_t last_pos;

  curr_loop.peaces.clear();

  // begin of loop
  loopPeace first;
  first.edge = curr_edge;
  first.face = m_topol->AdjElemToEdge (curr_edge, 0);
  m_topol->SetEdgeInfo (curr_edge, 1);

  // add begin peace of loop
  curr_loop.peaces.push_back(first);

  do 
  {
    last_pos = curr_loop.peaces.size()-1;
    last_edge = curr_loop.peaces[last_pos].edge;
    last_face = curr_loop.peaces[last_pos].face;

    // next face and edge
    getOppositeEdgeFace (last_edge, last_face, opp_edge, opp_face);

    // check if achieve the head of loop
    if (opp_face == first.face && opp_edge == first.edge)
      break;

    // check for auto intersection
    if (opp_face == first.face && opp_edge != first.edge)
      return false;

    loopPeace other_peace;
    other_peace.edge = opp_edge;
    other_peace.face = opp_face;
    m_topol->SetEdgeInfo (opp_edge, 1);

    // add begin peace of loop
    curr_loop.peaces.push_back(other_peace);

  } while (true);




  return true;
}

//
//////////////////////////////////////////////////////////////////////////
void whiskerWeaving::getOppositeEdgeFace( int edge, int face, 
                                          int &opp_edge, int &opp_face )
{

  
  // number of edges to face
  int n = m_topol->NumAdjEdgeToElem (face);

  // loop for edge of adjacent edges do current face
  for (int i = 0; i < n; ++i)
  {
    int curr_edge = m_topol->AdjEdgeToElem (face, i);
    if (curr_edge == edge)
    {
      opp_edge = m_topol->AdjEdgeToElem (face, (i+2)%n);
      break;
    }
  }

  // opposite face
  int face0 = m_topol->AdjElemToEdge (opp_edge, 0);
  int face1 = m_topol->AdjElemToEdge (opp_edge, 1);
  if (face0 == face)
    opp_face = face1;
  else
    opp_face = face0;
}
